package Concurrency2.Chapter05_Lock;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Instruction：死锁的检测
 * Author：@author MaLi
 */
public class T07_DeadLock {
    public static void main(String[] args) {
        CountDownLatch count = new CountDownLatch(2);

        ReentrantLock lock1 = new ReentrantLock(false);
        ReentrantLock lock2 = new ReentrantLock(false);
        //创建两把锁, 分别由两个线程交叉获取
        Thread t1 = new Thread(() -> {
            try {
                lock1.lockInterruptibly();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            try {
                try {
                    TimeUnit.SECONDS.sleep(1); //获取到锁T1之后, 暂停1秒
                    System.out.println(Thread.currentThread().getName() + " --> lock1, wating lock2");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                count.countDown();
                try {
                    //在main线程中, 中断当前线程的运行
                    lock2.lockInterruptibly();  //第二把锁设置为可被中断的, 一旦当前线程被中断, 那么可以被捕捉异常.
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                try {
                    System.out.println("T1 do something");
                } finally {
                    lock2.unlock();
                }
            } finally {
                lock1.unlock();
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            try {
                lock2.lockInterruptibly();

            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            try {
                try {
                    TimeUnit.SECONDS.sleep(1); //获取到锁T1之后, 暂停1秒
                    System.out.println(Thread.currentThread().getName() + " --> lock2, wating lock1");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                count.countDown();
                lock1.lock();
                try {
                    System.out.println("T2 do something");
                } finally {
                    lock1.unlock();
                }
            } finally {
                lock2.unlock();
            }
        }, "t2");

        t1.start();
        t2.start();
        try {
            count.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
        for (long deadlockedThread : deadlockedThreads) {
            System.out.println(deadlockedThread);
            ThreadInfo threadInfo = threadMXBean.getThreadInfo(deadlockedThread);
            System.out.println(threadInfo);
        }
        t1.interrupt();
    }
}
